import { ToolRegistry, ToolManager } from '../../Tool';
import registerCesiumAppTool from './Tools/index';
import { onSceneload } from './Utils/index';
import VGE from '../../VGE';
import { ViewSetting } from './Setting';
import { Camera } from './Camera';
import { Marker } from './Marker';
import { Polyline } from './Polyline';
import { Polygon } from './Polygon';
import { Layer } from './Layer';
import { Misc } from './Misc';
import { Weather } from './Weather';
import { Picker } from './Picker';
import { Polyhedron } from './Polyhedron';
// import * as BaiduImageryProvider from './Extensions/BaiduImageryProvider'

export default class CesiumApp {
	static async open(sceneData, callback) {
		try {
			const { sceneUrl, container, cameraParams, homeView, loadOptions } = sceneData;
			const { asyncService = false, ...other } = loadOptions || {};

			const t = Date.now();

			if (asyncService && this.viewer) {
				// 加载模型、底图等数据
				return this.loadService(sceneUrl).then((res) => {
					callback && callback(res);

					this.viewer.asyncLoadTime = Date.now() - t;
				});
			}

			const iCesium = (this.iCesium = await this.loadScript());
			const dom = await VGE.util.findOrCreateDom(container, true, true);

			const options = Object.assign(
				{
					infoBox: false,
					selectionIndicator: false,
					contextOptions: {
						webgl: { preserveDrawingBuffer: true }
						// requestWebgl2: true
					},
					navigation: false
				},
				other
			);
			const viewer = (this.viewer = new iCesium.Viewer(dom, options));
			viewer.scene.debugShowFramesPerSecond = false;

			// 加载模型、底图等数据
			this.loadService(sceneUrl).then((res) => {
				callback && callback(res);

				viewer.loadTime = Date.now() - t;
			});

			this.setting = new ViewSetting(viewer, iCesium);
			this.camera = new Camera(viewer, iCesium);
			this.marker = new Marker(viewer, iCesium);
			this.polyline = new Polyline(viewer, iCesium);
			this.polygon = new Polygon(viewer, iCesium);
			this.layer = new Layer(viewer, iCesium);
			this.misc = new Misc(viewer, iCesium);
			this.weather = new Weather(viewer, iCesium);
			this.picker = new Picker(viewer, iCesium);
			this.polyhedron = new Polyhedron(viewer, iCesium);

			this.homeViewParams = homeView;
			this.viewer.backStack = [];
			this.viewer.forwardStack = [];
			this.viewer._currentBaseline = null;

			setTimeout(() => {
				onSceneload(viewer, iCesium);
				registerCesiumAppTool();
				this.loadNavigation(viewer, iCesium);
			});

			// 同步前场景相机参数
			setTimeout(() => this.camera.flyTo(cameraParams), 1500);

			return this.viewer;
		} catch (e) {
			console.log(e.message);
		}
	}

	static async close() {
		this.toolManager.endActiveTool();
		const isDestroyed = this.viewer?.scene.isDestroyed();
		!isDestroyed && this.viewer?.scene.destroy();
		!isDestroyed && this.viewer?.cesiumNavigation.destroy();
		if (this.viewer) {
			this.viewer._container.innerHTML = '';
			this.viewer._container.onmousewheel = () => {};
			this.viewer = null;
		}
	}

	static async loadService(sceneUrl = []) {
		sceneUrl = Array.isArray(sceneUrl) ? sceneUrl : [sceneUrl];
		return Promise.allSettled(
			sceneUrl.map(async (item) => {
				if (typeof item === 'string') {
					item = {
						publishServer: 'SuperMap',
						serverType: 'SuperMap_rest3D',
						url: item
					};
				}
				const [serveType, dataType] = item.serverType.split('_');
				switch (serveType.toUpperCase()) {
					case 'OGC':
						return this.loadOGCService(dataType, item);
					case 'ARC':
						return this.loadARCService(dataType, item);
					case 'SUPERMAP':
					default:
						return this.loadSuperMapService(dataType, item);
				}
			})
		)
			.then((res) => Promise.resolve(res))
			.catch((res) => Promise.reject(res));
	}

	static async loadScript() {
		if (window.Cesium) return window.Cesium;
		return new Promise((resolve) => {
			const $link = document.createElement('link');
			$link.rel = 'stylesheet';
			window.document.head.appendChild($link);
			$link.href =
				'/graphics-engine/fusion-cdn/npm/supermap/11i/iClient3D/Cesium/Widgets/widgets.css';

			const $script = document.createElement('script');
			window.document.body.appendChild($script);
			$script.src = '/graphics-engine/fusion-cdn/npm/supermap/11i/iClient3D/Cesium/Cesium.js';
			$script.onload = () => resolve(window.Cesium);
		});
	}

	static async loadNavigation(viewer, iCesium) {
		const $script = document.createElement('script');
		window.document.body.appendChild($script);
		$script.src =
			'/graphics-engine/fusion-cdn/npm/supermap/11i/iClient3D/Cesium/ThirdParty/viewerCesiumNavigationMixin.js';
		$script.onload = () => {
			const opt = {};
			opt.defaultResetView = iCesium.Rectangle.fromDegrees(80, 22, 130, 50);
			// Only the compass will show on the map
			opt.enableCompass = true;
			opt.enableZoomControls = false;
			opt.enableDistanceLegend = false;
			opt.enableCompassOuterRing = true;
			viewer.extend(iCesium.viewerCesiumNavigationMixin, opt);
		};
	}

	static async loadOGCService(dataType, serviceData) {
		const viewer = this.viewer;
		const iCesium = this.iCesium;
		let imageryProvider;
		switch (dataType) {
			case 'WMTS': // Web切片地图服务Web Map Tile Service（WMTS）
				imageryProvider = new iCesium.WebMapTileServiceImageryProvider({
					...serviceData
				});
				break;
			case 'WMS': // Web 地图服务（WMS）
				imageryProvider = new iCesium.WebMapServiceImageryProvider({
					...serviceData,
					proxy: new iCesium.DefaultProxy('/proxy/')
				});
				break;
			case 'WCS': // Web地理覆盖服务（WCS）：提供的是包含了地理位置信息或属性的空间栅格图层，而不是静态地图的访问
				imageryProvider = new iCesium.SingleTileImageryProvider({
					...serviceData
				});
				break;
			case 'WFS': // Web 要素服务（WFS）：提供的是OGC标准的数据服务，不可视化的，只能用来查询、增删改数据
				// do something...
				break;
			case 'WPS': // 网络处理服务
				// do something...
				break;
			// case "Baidu":
			//   imageryProvider = new iCesium.BaiduImageryProvider({
			//     ...serviceData
			// })
			// break
			default:
				// URL 类型
				imageryProvider = new iCesium.UrlTemplateImageryProvider({
					...serviceData
				});
				break;
		}

		if (imageryProvider) {
			const layer = viewer.imageryLayers.addImageryProvider(imageryProvider);
			layer.type = 'ImageryProvider';
			layer.iid = '0x020000' + layer._imageryProvider._id;
			return Promise.resolve([layer]);
		}
	}

	static async loadSuperMapService(dataType, serviceData) {
		const viewer = this.viewer;
		const iCesium = this.iCesium;
		switch (dataType.toUpperCase()) {
			case 'REST3D': {
				let { url } = serviceData;
				url = url.endsWith('/realspace') ? url : url + '/realspace';
				// const sceneUrl = serviceData.url.endsWith("/realspace") ? serviceData.url : serviceData.url + "/realspace"
				const res = await viewer.scene.open(
					url,
					serviceData.sceneName || undefined,
					Object.assign(
						{
							autoSetView: true
						},
						serviceData?.options || {}
					)
				);
				this.setting.setHighlightColor(VGE.config.primaryColor);
				res.forEach((layer) => {
					if (!layer) return;
					layer.type = 'Layer';
					layer.iid = '0x010000' + layer.id;
				});
				return Promise.resolve(res);
			}
			case '3DDATASET-SCP': {
				// 图层级服务
				/**
				 * engineFrame中对应的
				 * publishServer: "SuperMap",
				 * serverType: "SuperMap_Layer",
				 */
				// 加载服务地址 URL 模板： http://host:8090/iserver/services/3D-{服务名称}/rest/realspace/datas/{图层名}/config
				let { url } = serviceData;
				const name = serviceData.name;
				url = url.endsWith('/config') ? url : url + '/config';
				// const Url = serviceData.url + '/config'
				const layer = await viewer.scene.addS3MTilesLayerByScp(
					url,
					Object.assign(
						{
							autoSetView: false,
							name
						},
						serviceData?.options || {}
					)
				);
				layer.type = 'Layer';
				layer.iid = '0x050000' + layer.id;
				return Promise.resolve([layer]);
			}
			case 'REST2D': {
				let { url } = serviceData;
				url = url.endsWith('/maps.json') ? url : url + '/maps.json';
				const { data } = await VGE.request(url);
				const res = data?.map(({ path: url, name }) => {
					const imageryProvider = new iCesium.SuperMapImageryProvider(
						Object.assign(
							{
								url,
								name
							},
							serviceData?.options || {}
						)
					);
					const layer = viewer.imageryLayers.addImageryProvider(imageryProvider);
					layer.type = 'ImageryProvider';
					layer.iid = '0x020000' + layer._imageryProvider._id;
					return layer;
				});
				return Promise.resolve(res);
			}
			case 'REST-MAPS':
			case '3DDATASET-IMG': {
				const url = serviceData.url;
				const name = serviceData.name;
				const imageryProvider = new iCesium.SuperMapImageryProvider(
					Object.assign(
						{
							url,
							name
						},
						serviceData?.options || {}
					)
				);
				const imageryLayer = viewer.imageryLayers.addImageryProvider(imageryProvider);
				imageryProvider.type = 'ImageryProvider';
				imageryProvider.iid = '0x060000' + imageryLayer.id;
				return Promise.resolve([imageryLayer]);
			}
			case 'MVT': {
				// 矢量瓦片
				const options = { name: 'mvtlayer', viewer };
				const layer = viewer.scene.addVectorTilesMap(Object.assign(options, serviceData));
				layer.type = 'VectorTilesMap';
				layer.iid = '0x030000' + layer._id;
				return Promise.resolve([layer]);
			}
			case 'TIN': {
				// iServer发布的TIN地形服务
				const options = { isSct: true, invisibility: true };
				const terrainProvider = new iCesium.CesiumTerrainProvider(
					Object.assign(options, serviceData)
				);
				const layer = viewer.terrainLayers.addTerrainProvider(terrainProvider);
				layer.type = 'TerrainLayer';
				layer.iid = '0x040000' + layer.id;
				return Promise.resolve([layer]);
			}
			default:
				// 矢量图等加载需要在scene打开后
				this.loadOGCService(dataType, serviceData);
				break;
		}
	}

	static async loadARCService(dataType, serviceData) {
		const viewer = this.viewer;
		const iCesium = this.iCesium;
		let token;
		// 方法基本和ogc中一致，增加一个token获取方法，其余不变
		const { data } = await VGE.request({
			method: 'POST',
			url: 'https://arcgis.fusionpaas.com/arcgis/sharing/rest/generateToken',
			data: 'username=arcgissim&password=Hdec_gissim&ip=&client=referer&referer=https%3A%2F%2Farcgis.fusionpaas.com%2Farcgis&expiration=20160&f=pjson',
			headers: {
				'Content-Type': 'application/x-www-form-urlencoded'
			}
		});
		token = data.token;
		switch (dataType) {
			case 'WMS': // 需要layers参数
				serviceData.url += `?token=${token}`;
				this.loadOGCService(dataType, serviceData);
				break;
			case 'WMTS':
				// wmts中需要设置瓦片设置的最大范围(全副范围)、
				// 要设置瓦片矩阵左上角 (如果不出图,有时候需要根据请求瓦片行列号,微调这个值)
				// 需要设置分辨率
				var provider = new iCesium.WebMapTileServiceImageryProvider({
					url: 'http://61.175.211.102/arcgis/rest/services/wzmap/map/MapServer/WMTS/tile/1.0.0/wzmap_map/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png', // 复制 2.5 中的地址
					layer: 'wzmap_map',
					style: 'default',
					tileMatrixSetID: 'default028mm',
					format: 'image/png',
					tilingScheme: new Cesium.GeographicTilingScheme(),
					maximumLevel: 21,
					tileMatrixLabels: [
						'1',
						'2',
						'3',
						'4',
						'5',
						'6',
						'7',
						'8',
						'9',
						'10',
						'11',
						'12',
						'13',
						'14',
						'15',
						'16',
						'17',
						'18',
						'19',
						'20',
						'21'
					] // 对应2.4中的tileMatrix Identifier属性
				});
				// 添加服务图层到视图中
				viewer.imageryLayers.addImageryProvider(provider);
				viewer.entities.removeAll();
				var positions = viewer.entities.add({
					name: 'position',
					position: Cesium.Cartesian3.fromDegrees(120.58468164419833, 27.842148925776648, 10000),
					point: {
						pixelSize: 5,
						color: Cesium.Color.RED,
						outlineColor: Cesium.Color.WHITE,
						outlineWidth: 2
					}
				});
				viewer.zoomTo(positions);
				break;
			case 'MAP': // 加载地图服务，MapServer结尾
				serviceData.token = token;
				loadArcGisData(viewer, iCesium, serviceData);
				break;
			case 'ElEV': // 加载高程服务，使用ArcGISTiledElevationTerrainProvider加载
				serviceData.token = token;
				var terrainProvider = new iCesium.ArcGISTiledElevationTerrainProvider({
					...serviceData
				});
				viewer.terrainProvider = terrainProvider;
				break;
			/* case 'IMAGE':// 影像服务 用UrlTemplateImageryProvider加载，模板格式待验证
        viewer.imageryLayers.addImageryProvider(
          new iCesium.UrlTemplateImageryProvider({
            url: 'https://landsat2.arcgis.com/arcgis/rest/services/Landsat8_Views/ImageServer/exportImage?bbox={westProjected}%2C{southProjected}%2C{eastProjected}%2C{northProjected}&size={width}%2C{height}&f=image',
            baseLayerPicker: false
          })
        )
        break */
			case 'SCENE':
			case 'FEATURE':
				// 可以获取图层信息，但是无法加载，feature server同理
				fetch(serviceData.url + `?token=${token}`)
					.then((res) => res.json())
					.then((data) => console.log(data));
				break;
			case 'CSW':
				break;
			case 'TMS':
				break;
			case 'WCS': // Web地理覆盖服务（WCS）：提供的是包含了地理位置信息或属性的空间栅格图层，而不是静态地图的访问
				break;
			case 'WMS-C': // Web 地图服务（WMS）
				break;
			case 'REST3D':
				break;
			default:
				this.loadOGCService(dataType, serviceData);
				break;
		}
	}

	static async loadGeoService(data) {
		const viewer = this.viewer;
		const iCesium = this.iCesium;
		return new Promise((resolve, reject) => {
			VGE.request
				.get(data.url)
				.then((res) => {
					iCesium.GeoJsonDataSource.load(res.data).then((datasource) => {
						viewer.dataSources.add(datasource);
						resolve(datasource);
					});
				})
				.catch((err) => {
					reject(err);
				});
		});
	}
}
CesiumApp.viewer = null;
CesiumApp.iCesium = null;
CesiumApp.tools = new ToolRegistry();
CesiumApp.toolManager = new ToolManager();
CesiumApp.homeViewParams = {};
CesiumApp.setting = null;
CesiumApp.camera = null;
CesiumApp.marker = null;
CesiumApp.polyline = null;
CesiumApp.polygon = null;
CesiumApp.layer = null;
CesiumApp.misc = null;
CesiumApp.picker = null;
CesiumApp.polyhedron = null;

function loadTianDiTuData(viewer, iCesium) {
	const imageryProvider = new iCesium.TiandituImageryProvider({
		mapStyle: iCesium.TiandituMapsStyle.CIA_C,
		token: '0472e419209b07d5a02ff3678c504c74'
	});
	viewer.imageryLayers.addImageryProvider(imageryProvider);

	return imageryProvider;
}

function loadArcGisData(viewer, iCesium, data) {
	console.log('loadArcGisData', arguments);
	const imageryProvider = new iCesium.ArcGisMapServerImageryProvider({
		...data
	});
	viewer.imageryLayers.addImageryProvider(imageryProvider);

	return imageryProvider;
}
